﻿using DevLib.SuperTool;
using DevLib.TestCase;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


/** 
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
 * Description: 
 * Author: Heller (HellerSong@outlook.com)
 * CreationTime: 3/4/2015 2:14:32 PM
 ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 
 **/
namespace DevLib.FileTool
{
    public class FileOM
    {
        private FileOM() { }


        public static void DeleteWholeDirectory(String path)
        {
            StrCheck.CheckChainDirOperable(path);

            Directory.Delete(path, true);
        }
        public static void DeleteToCleanDirectory(String path)
        {
            StrCheck.CheckChainDirOperable(path);

            String[] allChildDirectories = Directory.GetDirectories(path);
            String[] allChildFiles = Directory.GetFiles(path);

            foreach (String s in allChildDirectories)
                Directory.Delete(s, true);
            foreach (String s in allChildFiles)
                File.Delete(s);
        }
        public static void DeleteFilesButRemainDirectoryStructure(String path)
        {
            StrCheck.CheckChainDirOperable(path);

            // Delete all files recursive of each sub directory.
            String[] allChildDirectories = Directory.GetDirectories(path);
            String[] allChildFiles = Directory.GetFiles(path);

            foreach (String s in allChildFiles)
                File.Delete(s);
            foreach (String s in allChildDirectories)
                DeleteFilesButRemainDirectoryStructure(s);
        }

        public static void CopyFileToDestDirectory(String sourceFile, String destPath)
        {
            /* 
             * There are three copy situation
             *   example 1: there is no such file at destination folder, then copy directly
             *   example 2: the file at destination folder with the latest version, then give up
             *   example 3: the file at source folder with the latest version, then copy and override it
             */
            StrCheck.CheckChainFileOperable(sourceFile);
            StrCheck.CheckChainDirIllegal(destPath);

            FileInfo sourceFileInfo = new FileInfo(sourceFile);
            String sourceFileName = sourceFileInfo.Name;
            String destFile = Path.Combine(destPath, sourceFileName);
            DateTime sourceFileModifyDate = sourceFileInfo.LastWriteTimeUtc;
            DateTime destFileModifyDate;

            if (File.Exists(destFile))  // means directory is existed
            {
                destFileModifyDate = (new FileInfo(destFile)).LastWriteTimeUtc;
                if (sourceFileModifyDate.CompareTo(destFileModifyDate) > 0)
                    File.Copy(sourceFile, destFile, true);  // Copy and override file with the latest version
                // else do nothing to give up copy
            }
            else
            {
                DirOM.MakeDirectory(destPath);  // Makesure the directory is existed
                File.Copy(sourceFile, destFile);
            }
        }
        public static void CopyFileWithNewName(String sourceFile, String newName)
        {
            StrCheck.CheckChainFileOperable(sourceFile);
            StrCheck.CheckChainDirIllegal(newName);

            String newFile = Path.Combine(DirOM.GetParrentDirectory(sourceFile), newName);
            File.Copy(sourceFile, newFile, true);
        }
        public static void CopyDirectoryWith128Threads(String sourcePath, String destPath)
        {
            StrCheck.CheckChainDirOperable(sourcePath);
            StrCheck.CheckChainDirIllegal(destPath);

            String copyOption = " /e /mt:128";
            String copyPath = "\"" + sourcePath + "\" \"" + destPath + "\"";

            // Move the dir and file structure in source folder to dest folder
            DirOM.MakeDirectory(destPath);
            ProcessOM.LaunchCmd("robocopy.exe " + copyPath + copyOption);
        }

        public static void CopySelectedFilesRemainStructure(String[] keywordList, String sourcePath, String destPath)
        {
            // It will remain directory structure under dest path

            DirOM.MakeDirectory(destPath);
            FileOM.DeleteToCleanDirectory(destPath);
            Dictionary<String, String> copyResult = new Dictionary<String, String>();
            String sourceFile;
            String destFile;

            foreach (String keyword in keywordList)
            {
                sourceFile = SearchFileByUniqueIdentifier(sourcePath, keyword);
                if (sourceFile != null) // We searched the exactly file
                {
                    destFile = sourceFile.Replace(sourcePath, destPath);
                    DirOM.MakeDirectory((new FileInfo(destFile)).Directory.FullName);
                    File.Copy(sourceFile, destFile);
                    copyResult.Add(sourceFile, "Copyed");
                }
                else
                    copyResult.Add(keyword, "No File");
            }
            //HSGlobal.tableFormatCellAverageLength("File", "CopyResult");
            //foreach (var pair in copyResult)
            //    HSGlobal.tableFormatCellAverageLength(pair.Key, pair.Value);
        }
        public static void CopySelectedFilesToOneFolder(String[] keywordList, String sourcePath, String destPath)
        {

        }

        // Search
        // [Upgrade] How about move to internal variable "searchResult" for recursion
        // [Upgrade] When so huge number of file collection, how to more effectivly?
        public static String SearchFileByExactlyName(String searchingPath, String fileName)
        {
            StrCheck.CheckChainDirOperable(searchingPath);
            StrCheck.CheckChainDirIllegal(fileName);

            String searchResult = null;

            String[] files = Directory.GetFiles(searchingPath, fileName, SearchOption.AllDirectories);
            if (files.Length > 0)
                searchResult = files[0];

            return searchResult;
        }
        public static String SearchFileByUniqueIdentifier(String searchingPath, String identifierString)
        {

            StrCheck.CheckChainDirOperable(searchingPath);
            StrCheck.CheckChainDirIllegal(identifierString);

            String searchResult = null;

            // Search in this level child files
            foreach (String filePath in Directory.GetFiles(searchingPath))
            {
				String id = DevRegex.GetMatchedString(new FileInfo(filePath).Name, DevRegex.MatchSentencePositiveInteger);
                if (id.Length > 0)     // you must exclude there is not any number among file name
                    if (identifierString.Equals(id))
                        return searchResult = filePath;
            }

            // Search into child directories
            foreach (String dir in Directory.GetDirectories(searchingPath))
            {
                searchResult = SearchFileByUniqueIdentifier(dir, identifierString);
                if (searchResult != null)
                    break;
            }

            return searchResult;
        }

        public static void RenameAllFilesReplace(String path, String oldString, String newString)
        {
            StrCheck.CheckChainDirOperable(path);
            StrCheck.CheckChainDirIllegal(oldString);
            StrCheck.CheckChainDirIllegal(newString);

            String[] allChildFiles = Directory.GetFiles(path);
            String newFile;
            String oldFileName; // Fix Bug, if full path conatin subString, not only file name contains, it goes wrong 
            String fileExtension;

            foreach (String childFile in allChildFiles)
            {
                oldFileName = Path.GetFileNameWithoutExtension(childFile);
                fileExtension = Path.GetExtension(childFile);
                if (oldFileName.Contains(oldString))
                {
                    newFile = Path.Combine(path, oldFileName.Replace(oldString, newString)) + fileExtension;
                    File.Move(childFile, newFile);
                }
                else
                    Console.WriteLine("NOT RENAME: " + childFile);
            }
        }
        public static void RenameAllFilesInsertSubString(String path, int afterTheIndex, String newString)
        {
            StrCheck.CheckChainDirOperable(path);
            StrCheck.CheckChainDirIllegal(newString);

            String[] allChildFiles = Directory.GetFiles(path);
            String newFile;
            String oldFileName;

            foreach (String childFile in allChildFiles)
            {
                oldFileName = Path.GetFileName(childFile);
                newFile = Path.Combine(path, oldFileName.Insert(afterTheIndex + 1, newString));
                File.Move(childFile, newFile);
            }
        }
        //public static void renaeAllFilesInsertNumber(String dirPath, params int[] startNumber)
        //{
        //    // default start number is: 1, if you do not specify params
        //    String[] allChildFiles = Directory.GetFiles(dirPath);
        //    String newFileName;
        //    int padWidth;

        //    //Array.Sort(allChildFiles);
        //    for (int i = 0; i < allChildFiles.Length; i++)
        //    {
        //        if (startNumber.Length > 0)
        //        {
        //            padWidth = (allChildFiles.Length + startNumber[0]).ToString().Length;
        //            newFileName = Path.GetFileName(allChildFiles[i]).Insert(0, (startNumber[0] + i).ToString().PadLeft(padWidth, '0'));
        //        }
        //        else
        //        {
        //            padWidth = allChildFiles.Length.ToString().Length;
        //            newFileName = Path.GetFileName(allChildFiles[i]).Insert(0, (i + 1).ToString().PadLeft(padWidth, '0'));
        //        }
        //        File.Move(allChildFiles[i], Path.Combine(dirPath, newFileName));
        //    }
        //}
        public static void RenameAllFilesDeleteIndexChar(String path, int charIndex, params int[] deleteCount)
        {
            StrCheck.CheckChainDirOperable(path);

            String[] allChildFiles = Directory.GetFiles(path);
            String newFileName;

            foreach (String childFile in allChildFiles)
            {
                List<char> nameArray = new List<char>(Path.GetFileName(childFile).ToCharArray());
                if (deleteCount.Length > 0)
                    nameArray.RemoveRange(charIndex, deleteCount[0]);
                else
                    nameArray.RemoveAt(charIndex);
                newFileName = new String(nameArray.ToArray());
                File.Move(childFile, Path.Combine(path, newFileName));
            }
        }
        //public static void renameAllFilesSerialNumber001(String dirPath, params int[] numberLength)
        //{
        //    String tempDirectory = dirPath + "temp";
        //    deleteWholeDirectory(tempDirectory);
        //    Console.WriteLine(tempDirectory);
        //    copyDirectoryWith128Threads(dirPath, tempDirectory);
        //    deleteToCleanDirectory(dirPath);

        //    FileInfo fileInfo;
        //    String newFilePath;
        //    String fileExtension;
        //    String[] allChildFiles = Directory.GetFiles(tempDirectory);
        //    int padWidth = allChildFiles.Length.ToString().Length;

        //    Array.Sort(allChildFiles);
        //    for (int i = 0; i < allChildFiles.Length; i++)
        //    {
        //        fileInfo = new FileInfo(allChildFiles[i]);
        //        fileExtension = fileInfo.Name.Split('.')[1];
        //        if (numberLength.Length > 0)
        //            newFilePath = dirPath + "\\" + (i + 1).ToString().PadLeft(numberLength[0], '0') + "." + fileExtension;
        //        else
        //            newFilePath = dirPath + "\\" + (i + 1).ToString().PadLeft(padWidth, '0') + "." + fileExtension;
        //        File.Copy(allChildFiles[i], newFilePath);
        //    }
        //    deleteWholeDirectory(tempDirectory);
        //}



    }
}
